package io.jt808.netty;

import io.jt808.proto.WrapperHeader;
import io.netty.buffer.ByteBuf;
import io.netty.buffer.ByteBufUtil;
import io.netty.channel.ChannelHandlerContext;
import io.jt808.proto.Wrapper;
import io.jt808.util.Tools;
import io.norland.annotations.Proto;
import io.norland.buffer.AutoBuffer;
import io.norland.proto.IProto;
import io.norland.proto.ProtoCreator;
import io.norland.server.ChannelHolder;
import io.norland.server.ProtoFrameCodec;
import lombok.extern.slf4j.Slf4j;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

import java.util.List;

@Component
@Slf4j
public class Jt808ProtoFrameCodec extends ProtoFrameCodec {

    private Logger logger = Logger.getLogger(Jt808ProtoFrameCodec.class);

    /**
     * 未做分包处理
     */
    @Override
    protected void encode(ChannelHandlerContext ctx, Object msg, ByteBuf out) throws Exception {
        Wrapper message = new Wrapper();
        byte[] data = null;
        int messageId = 0x8001;//通用应答
//        if (msg instanceof byte[]) {
//            data = (byte[]) msg;
//        }
        if (msg instanceof IProto) {
            data = ((IProto) msg).writeToBytes();
            messageId = Integer.valueOf(ProtoCreator.getProtoName(msg), 16);
        }
        if (data == null) {
            return;
        }
        WrapperHeader header = new WrapperHeader();
        header.setMessageId(messageId);
        header.setEncryption(0);
        header.setMessageBodyProperty(0x0000);
        header.setMessageLength(0);
//        header.setPackage(true);
//        header.setMessagePacketNo(1);
//        header.setMessageTotalPacketsCount(1);
        header.setPackage(false);
        header.setSimId(ChannelHolder.getTerminalSerialNoByChannelId(ctx.channel().id()));
        message.setMessageContents(data);
        message.setHeader(header);
        byte[] bytes = message.writeToBytes();
        out.writeBytes(bytes);
        log.info("SEND MASSAGE: " + Tools.ToHexFormatString(bytes));
    }

    @Override
    protected void decode(ChannelHandlerContext ctx, ByteBuf in, List<Object> out) throws Exception {
        if (in == null) return;
        in.markReaderIndex();
        while (in.isReadable()) {
            in.markReaderIndex();
            int packetBeginIndex = in.readerIndex();
            byte tag = in.readByte();
            // 搜索包的开始位置
            if (tag == Wrapper.SEPARATOR && in.isReadable()) {
                tag = in.readByte();
                // 寻找包的结束
                while (tag != Wrapper.SEPARATOR) {
                    if (!in.isReadable()) {
                        in.resetReaderIndex(); // 没有找到结束包，等待下一次包
                        logger.info("不完整包: " + Tools.ToHexFormatString(ByteBufUtil.getBytes(in)));
                        return;
                    }
                    tag = in.readByte();
                }
                int packetEndIndex = in.readerIndex();
                int packetLength = packetEndIndex - packetBeginIndex;
                if (packetLength >= Wrapper.MIN_LENGTH) {
                    in.resetReaderIndex();
                    byte[] bytes = new byte[packetLength];
                    in.readBytes(bytes);
                    Wrapper message = new Wrapper();
                    message.readFromBuf(new AutoBuffer(bytes));
                    log.info("Read Message: " + Tools.ToHexFormatString(bytes));
                    if (message.getErrorMessage() != null) {
                        logger.info(message.getErrorMessage());
                        continue;
                    }
                    out.add(message); // 触发接收Message的事件
                } else {
                    // 说明两个0x7E之间的数据是不可信的
                    logger.info("两个0x7E之间的数据是不可信的");
                    in.resetReaderIndex();
                    in.skipBytes(packetLength - 1);
                }
            }
        }
    }
}
